1-5 Numpy教程

1. Numpy是什么?

Numerical Python 的缩写

  • 一个开源的Python科学计算库

  • 使用numpy可以方便的使用数组、矩阵进行计算

  • 包含线性代数、傅里叶变换、随机数生成等大量函数

2. 为什么使用Numpy?

对于同样的数值计算任务,使用numpy比直接编写python代码实现 优点:

  • 代码更简洁: numpy直接以数组、矩阵为粒度计算并且支持大量的数学函数,而python需要用for循环从底层实现;

  • 性能更高效: numpy的数组存储效率和输入输出计算性能,比python使用list好很多;numpy的大部分代码都是c语言实现的,这是numpy比python高效的原因

numpy是python各种数据科学类库的基础库

  • 比如SciPy、Scikit-Learn、tenorflow、paddlepaddle等

  • 如果不会numpy,这些库的深入理解都会遇到障碍

3. 安装numpy

conda install numpy

(关于conda的使用可以看上期教程)

4. numpy 与 原生python的性能对比

# 引入numpy的包 
import numpy as np
# 查看numpy的版本
np.__version__
# 使用python原生语法
# 实现两个数组相加
def python_sum(n):
    a = [i**2 for i in range(n)]
    b = [i**3 for i in range(n)]
    c = [a[i]+b[i] for i in range(n)]
    return c
    
# 测试
python_sum(10)

[0, 2, 12, 36, 80, 150, 252, 392, 576, 810]

# 使用numpy实现上面功能
def numpy_sum(n):
    a = np.arange(n) ** 2
    b = np.arange(n) ** 3
    c = a+b
    return c
# 测试
numpy_sum(10)

array([ 0, 2, 12, 36, 80, 150, 252, 392, 576, 810], dtype=int32)

# 执行1000次  输入执行时间 对比性能
# %timeit 魔法函数 
%timeit python_sum(1000)

411 µs ± 3.31 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit numpy_sum(1000)

6.51 µs ± 57 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

可以看出使用numpy进行计算要比原生Python快得多,而且数据量越大,效果越明显

5.numpy核心ndarray对象

ndarray对象:

  • numpy的核心数据结构,叫做array就是数组,array对象可以是一维数组,也可以是多维数组

  • python的list也可以实现相同的功能,但是array的优势在于性能好,包含数组元数据信息、大量的便捷函数

  • 成为 Scipy、Pandas、scilit-learn、tensorflow、paddlepaddle等框架的通用底层语言

  • numpy的array和python的list的一个区别是它的元素必须都是同一种数据类型,这也是numpy高性能的一个原因

ndarray属性

  • shape 返回一个元组 表示array的形状

  • ndim 返回一个数字 表示array的维度的数目

  • size 返回一个数字 表示array中所有数据元素的数目

  • dtype array中元素的数据类型

  • itemsize 表示数组中每个元素的字节大小

array本身支持的大量操作和函数

  • 直接逐元素的加减乘除等算数操作

  • 更好用的面向多维的数组索引

  • 求sum/mean等聚合函数

  • 线性代数函数、比如求解逆矩阵、求解方程组

6. 创建array的方法

  • 从Python的列表list和嵌套列表创建array

  • 使用预定函数arange、linspace等创建等差数组

  • 使用ones、ones_like、zeros、zeros_like、empty、empty_like、full、full_like、eye等函数创建

  • 生成随机数的np.random模块创建

6.1 使用np.array()

import numpy as np
# 创建一个一维数组
x = np.array([1, 2, 3 ,4, 5])
x

array([1, 2, 3, 4, 5])

# 创建一个二维数组
y = np.array(
    [
        [1, 2, 3, 4],
        [5, 6, 7 ,8]
    ]
)
y

array([[1, 2, 3, 4], [5, 6, 7, 8]])

# 数组的形状  1行5列
x.shape

(5,)

# 数组的形状  2行4列
y.shape

(2, 4)

# x是1维数组
x.ndim

1

# y是2维数组
y.ndim

2

# x一共有5个数据
x.size

5

# y中一共有8个数据
y.size

8

# x中的数据类型
x.dtype

dtype(’int32’)

# y中的数据类型
y.dtype

dtype(’int32’)

# 表示数组中每个元素的字节大小
y.itemsize

4

6.2 使用np.arange(start,stop,step,dtype) 生成等差数组

  • start 表示开始的数(包含) 默认从0开始

  • stop 表示结束的数(不包含)

  • step 指定步长 默认为1

  • dtype 指定数据类型

 # 创建了一个从0到9的数组 不包含10  步长默认为1
np.arange(10)

array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

# [0,10)区间  左闭右开   指定步长为2
np.arange(0, 10, 2)

array([0, 2, 4, 6, 8])

# reshape 可以改变数组的形状
# 将一维数组 改成 2行5列的 2维数组
np.arange(10).reshape(2,5)

array([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]])

6.3 使用np.linspace(start,stop,num,endpoint) 创建等差数组-指定数量

  • start 起始值

  • stop 结束值

  • num 要生成的等间隔样例数量,默认为50

  • endpoint 序列中是否包含stop值, 默认为true

np.linspace(0,10)

array([ 0. , 0.20408163, 0.40816327, 0.6122449 , 0.81632653, 1.02040816, 1.2244898 , 1.42857143, 1.63265306, 1.83673469, 2.04081633, 2.24489796, 2.44897959, 2.65306122, 2.85714286, 3.06122449, 3.26530612, 3.46938776, 3.67346939, 3.87755102, 4.08163265, 4.28571429, 4.48979592, 4.69387755, 4.89795918, 5.10204082, 5.30612245, 5.51020408, 5.71428571, 5.91836735, 6.12244898, 6.32653061, 6.53061224, 6.73469388, 6.93877551, 7.14285714, 7.34693878, 7.55102041, 7.75510204, 7.95918367, 8.16326531, 8.36734694, 8.57142857, 8.7755102 , 8.97959184, 9.18367347, 9.3877551 , 9.59183673, 9.79591837, 10. ])

np.linspace(0, 10, 5)

array([ 0. , 2.5, 5. , 7.5, 10. ])

6.4 使用ones、ones_like、zeros、zeros_like、empty、empty_like、full、full_like、eye等函数创建

# 使用ones创建全是1的数组
np.ones(10)

array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])

np.ones((2, 4))

array([[1., 1., 1., 1.], [1., 1., 1., 1.]])

# 使用ones_like创建形状相同的数组
np.ones_like(x)

array([1, 1, 1, 1, 1])

np.ones_like(y)

array([[1, 1, 1, 1], [1, 1, 1, 1]])

# 使用zeros创建全是0的数组
np.zeros(10)

array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])

np.zeros((2,4))

array([[0., 0., 0., 0.], [0., 0., 0., 0.]])

# 使用zeros_like创建形状相同的数组
np.zeros_like(x)

array([0, 0, 0, 0, 0])

np.zeros_like(y)

array([[0, 0, 0, 0], [0, 0, 0, 0]])

# 使用empty创建未初始化的数组
# 注意:数据是未初始化的,里面的值可能是随机值不要用
np.empty(10)

array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])

np.empty((2, 3))

array([[0., 0., 0.], [0., 0., 0.]])

# 使用empty_like创建形状相同的数组
np.empty_like(x)

array([1767994469, 170816364, 538976266, 1701139232, 1936474400])

np.empty_like(y)

array([[ 24385651, 8127092, 60818051, 27328636], [ 6226044, 6946940, 19464275, -637261490]])

# 使用full创建指定值的数组
np.full(10, 666)

array([666, 666, 666, 666, 666, 666, 666, 666, 666, 666])

np.full((2, 4), 666)

array([[666, 666, 666, 666], [666, 666, 666, 666]])

# 使用full_like创建形状相同的数组
np.full_like(x, 666)

array([666, 666, 666, 666, 666])

np.full_like(y, 666)

array([[666, 666, 666, 666], [666, 666, 666, 666]])

# 使用 eye 函数创建 对角线的地方为1,其余的地方为0.
np.eye(5)

array([[1., 0., 0., 0., 0.], [0., 1., 0., 0., 0.], [0., 0., 1., 0., 0.], [0., 0., 0., 1., 0.], [0., 0., 0., 0., 1.]])

6.5 np.random模块创建

# 设置随机种子  作用是:使得每次随机的结果固定
np.random.seed(666)
# 返回数据在[0,1)之间  包含0 不包含1
np.random.rand(5)

array([0.70043712, 0.84418664, 0.67651434, 0.72785806, 0.95145796])

# 随机生成 2行5列的2维数组  数据在[0,1)之间
np.random.rand(2,5)

array([[0.0127032 , 0.4135877 , 0.04881279, 0.09992856, 0.50806631], [0.20024754, 0.74415417, 0.192892 , 0.70084475, 0.29322811]])

# 生成随机整数  区间范围:[2,5) 左闭右开  包含2不包含5
np.random.randint(2,5)

2

# 指定shape
np.random.randint(2,5,5)

array([2, 2, 2, 2, 2])

#uniform() 在 [low,high) 之间 生成均匀分布的数字
np.random.uniform(2,5,10)

array([4.30223703, 4.85969412, 2.87292148, 4.54334592, 3.04928571, 4.77169077, 2.88468359, 3.57314184, 4.82761689, 2.22421847])

# 前面的 2, 5 表示 取值的区间范围 [2,5)
# 后面的(2,5) 是指定的shape
np.random.uniform(2,5,(2,5))

array([[2.82938752, 3.40275649, 2.94744596, 3.17048776, 2.80498943], [4.26099152, 4.0002124 , 4.61863861, 3.56329157, 4.25061275]])

# randn  返回数据具有标准正态分布 
# 即:均值为0 方差为1
np.random.randn(5)

array([-1.21715355, -0.99494737, -1.56448586, -1.62879004, 1.23174866])

np.random.randn(2,5)

array([[-0.91360034, -0.27084407, 1.42024914, -0.98226439, 0.80976498], [ 1.85205227, 1.67819021, -0.98076924, 0.47031082, 0.18226991]])

# normal()  可以指定均值和标准差差
np.random.normal(1,10,5)

array([-7.43882492, 3.0996833 , 3.29586662, 3.63076422, 22.66332222])

np.random.normal(1,10,(2,5))

array([[ -9.48875925, -17.47684423, 6.34015028, -10.95748024, -1.89157372], [ -1.43327034, -6.42666527, 13.07905106, 11.27877114, 1.57388197]])

# choice 从给定的数组里 生成随机结果
np.random.choice(5, 3)
# 等同于 np.random.choice(0, 5, 3)  在[0,5)的区间范围内 生成3个数据

array([0, 1, 2])

np.random.choice(5, (2, 3))

array([[0, 1, 0], [0, 1, 2]])

np.random.choice([1,3,5,2,3], 3)

array([3, 3, 5])

# shuffle 把一个数组进行随机排列
a = np.arange(10)
np.random.shuffle(a) 
a

array([6, 3, 5, 1, 0, 8, 4, 9, 2, 7])

a = np.arange(20).reshape(4, 5)
a

array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]])

# 如果数组是多维的  则只会在第一维度打散数据
np.random.shuffle(a)
a

array([[10, 11, 12, 13, 14], [15, 16, 17, 18, 19], [ 5, 6, 7, 8, 9], [ 0, 1, 2, 3, 4]])

# permutation 把一个数组进行随机排列  或者数字的全排列
np.random.permutation(10)

array([4, 9, 8, 7, 3, 5, 6, 1, 0, 2])

arr = np.arange(9).reshape((3,3))
arr

array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])

# permutation 与 shuffle 函数功能相同  区别在于:
# 注意 permutation不会更改原来的arr 会返回一个新的copy
np.random.permutation(arr)

array([[3, 4, 5], [6, 7, 8], [0, 1, 2]])

arr

array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])

7. numpy的数组索引

三种索引方法:

  • 基础索引

  • 神奇索引

  • 布尔索引

7.1 基础索引

# 一维向量
x = np.arange(10)
x

array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

# 二维向量 一般用大写字母
Y = np.arange(20).reshape(4, 5)
Y

array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]])

# 取索引从2 到 倒数第一 个(不包含倒数第一个)
x[2:-1]

array([2, 3, 4, 5, 6, 7, 8])

# 取 第1行第1列的数 
# 注意: 索引是从0开始的    我们日常所说的第1行 它的索引值是0
Y[0, 0]

0

# 取索引为第2行的数据
Y[2]

array([10, 11, 12, 13, 14])

# 取索引为第2列的数据
Y[:,2]

array([ 2, 7, 12, 17])

注意:切片的修改会修改原来的数组

原因: numpy经常要处理大数组,避免每次都复制

# 修改x的第0-2(不包含2)数据
x[:2] = 666
x

array([666, 666, 2, 3, 4, 5, 6, 7, 8, 9])

7.2 神奇索引

就是: 用整数数组进行的索引

x = np.arange(10)
x

array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

x[[2,3,4]]

array([2, 3, 4])

indexs = np.array([[0,2],[1,3]])
x[indexs]

array([[0, 2], [1, 3]])

实例 : 获取数组中最大的前n个数字

# 随机生成1-100之间的10个数字
arr = np.random.randint(1, 100, 10)
arr

array([37, 30, 76, 20, 63, 80, 42, 83, 91, 67])

# arr.argsort() 会返回排序后的索引index
# 取最大值对应的3个下标
arr.argsort()[-3:]

array([5, 7, 8], dtype=int64)

arr[arr.argsort()[-3:]]

array([80, 83, 91])

二维数组

Y = np.arange(20).reshape(4, 5)
Y

array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]])

# 筛选多行 列可以省略
Y[[0,2]]

array([[ 0, 1, 2, 3, 4], [10, 11, 12, 13, 14]])

Y[[0,2],:]

array([[ 0, 1, 2, 3, 4], [10, 11, 12, 13, 14]])

# 筛选多列 行不能省略
Y[:,[0, 2]]

array([[ 0, 2], [ 5, 7], [10, 12], [15, 17]])

# 同时指定行列
Y[[0,2,3],[1,2,3]]

array([ 1, 12, 18])

7.3布尔索引

x = np.arange(10)
x

array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

# 返回bool值的数组
x>5

array([False, False, False, False, False, False, True, True, True, True])

x[x>5]

array([6, 7, 8, 9])

# 通过条件进行赋值
x[x<=5] = 0
x[x>5] = 1
x

array([0, 0, 0, 0, 0, 0, 1, 1, 1, 1])

x = np.arange(10)
x[x<5] += 20
x

array([20, 21, 22, 23, 24, 5, 6, 7, 8, 9])

Y = np.arange(20).reshape(4, 5)
Y

array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]])

Y > 5

array([[False, False, False, False, False], [False, True, True, True, True], [ True, True, True, True, True], [ True, True, True, True, True]])

# Y>5的boolean数组 既有行又有列 因此返回的是 行列一维数组
Y[Y>5]

array([ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])

Y[:, 3]

array([ 3, 8, 13, 18])

Y[:, 3]>5

array([False, True, True, True])

# 把第3列大于5的行数据筛选出来
Y[:, 3][Y[:, 3]>5]

array([ 8, 13, 18])

条件的组合

x = np.arange(10)
x

array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

condition = (x%2==0)| (x>7)
condition

array([ True, False, True, False, True, False, True, False, True, True])

x[condition]

array([0, 2, 4, 6, 8, 9])

8. numpy的操作与函数

A  = np.arange(6).reshape(2, 3)
A

array([[0, 1, 2], [3, 4, 5]])

# 相当于 A中的每个数据都+1
A+1

array([[1, 2, 3], [4, 5, 6]])

# 相当于 A中的每个数据都*3
A*3

array([[ 0, 3, 6], [ 9, 12, 15]])

np.sin(A)

array([[ 0. , 0.84147098, 0.90929743], [ 0.14112001, -0.7568025 , -0.95892427]])

np.exp(A)

array([[ 1. , 2.71828183, 7.3890561 ], [ 20.08553692, 54.59815003, 148.4131591 ]])

B  = np.arange(6,12).reshape(2, 3)
B

array([[ 6, 7, 8], [ 9, 10, 11]])

# 对应位置元素相加
A + B

array([[ 6, 8, 10], [12, 14, 16]])

# 对应位置元素相减
A - B 

array([[-6, -6, -6], [-6, -6, -6]])

# 对应位置元素相乘
A*B

array([[ 0, 7, 16], [27, 40, 55]])

numpy的数学统计函数

arr = np.arange(12).reshape(3,4)
arr

array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]])

# 求和
np.sum(arr)

66

# 乘积
np.prod(arr)

0

# 累加
np.cumsum(arr)

array([ 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 66], dtype=int32)

# 累乘
np.cumprod(arr)

array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype=int32)

# 最小值
np.min(arr)

0

# 最大值
np.max(arr)

11

# 求取数列第?分位的数值
np.percentile(arr,[25,50,75])

array([2.75, 5.5 , 8.25])

# 功能同上面  只不过范围为0-1直接
np.quantile(arr,[0.25,0.5,0.75])

array([2.75, 5.5 , 8.25])

#中位数
np.median(arr)

5.5

# 平均值
np.mean(arr)

5.5

# 标准差
np.std(arr)

3.452052529534663

# 方差
np.var(arr)

11.916666666666666

# 加权平均
# weights 的 shape 需要和 arr 一样
weights = np.random.rand(*arr.shape)
np.average(arr, weights=weights)

5.355698948848374

9.numpy的axis参数

axis=0代表行 axis=1 代表列

对于sum/mean/media等聚合函数:

  • axis=0 代表把行消解掉,axis=1 代表把列消解掉

  • axis=0 代表跨行计算, axis=1 代表跨列计算

arr = np.arange(12).reshape(3,4)
arr

array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]])

arr.sum(axis=0)

array([12, 15, 18, 21])

arr.sum(axis=1)

array([ 6, 22, 38])

arr.cumsum(axis=0)

array([[ 0, 1, 2, 3], [ 4, 6, 8, 10], [12, 15, 18, 21]], dtype=int32)

arr.cumsum(axis=1)

array([[ 0, 1, 3, 6], [ 4, 9, 15, 22], [ 8, 17, 27, 38]], dtype=int32)

mean = np.mean(arr, axis=0)
mean

array([4., 5., 6., 7.])

std = np.std(arr,axis=0)
std

array([3.26598632, 3.26598632, 3.26598632, 3.26598632])

result = arr-mean
result

array([[-4., -4., -4., -4.], [ 0., 0., 0., 0.], [ 4., 4., 4., 4.]])

10.numpy给数组添加维度

arr = np.arange(5)
arr

array([0, 1, 2, 3, 4])

arr.shape

(5,)

方法1 np.newaxis关键字

np.newaxis 就是None的别名

np.newaxis is None

True

np.newaxis == None

True

arr[np.newaxis, :]

array([[0, 1, 2, 3, 4]])

arr[np.newaxis, :].shape

(1, 5)

# 给一维向量添加一个列维度
arr[:, np.newaxis]

array([[0], [1], [2], [3], [4]])

arr[:,np.newaxis].shape

(5, 1)

方法2 np.expand_dims 方法

np.expand_dims(arr, axis=0)

array([[0, 1, 2, 3, 4]])

np.expand_dims(arr,axis=0).shape

(1, 5)

np.expand_dims(arr,axis=1)

array([[0], [1], [2], [3], [4]])

np.expand_dims(arr,axis=1).shape

(5, 1)

方法3 np.reshape

np.reshape(arr, (1,5))

array([[0, 1, 2, 3, 4]])

# -1表示 自动计算出结果  
np.reshape(arr,(1,-1))

array([[0, 1, 2, 3, 4]])

np.reshape(arr,(1,-1)).shape

(1, 5)

np.reshape(arr,(-1,1))

array([[0], [1], [2], [3], [4]])

np.reshape(arr,(-1,1)).shape

(5, 1)

11.数组合并操作

合并行

a = np.arange(6).reshape(2,3)
b = np.arange(6,18).reshape(4,3)
a

array([[0, 1, 2], [3, 4, 5]])

b

array([[ 6, 7, 8], [ 9, 10, 11], [12, 13, 14], [15, 16, 17]])

np.concatenate([a,b])

array([[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11], [12, 13, 14], [15, 16, 17]])

np.vstack([a,b])

array([[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11], [12, 13, 14], [15, 16, 17]])

np.row_stack([a,b])

array([[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11], [12, 13, 14], [15, 16, 17]])

合并列

a = np.arange(12).reshape(3,4)
a

array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]])

b = np.arange(12,18).reshape(3,2)
b

array([[12, 13], [14, 15], [16, 17]])

np.concatenate([a,b],axis=1)

array([[ 0, 1, 2, 3, 12, 13], [ 4, 5, 6, 7, 14, 15], [ 8, 9, 10, 11, 16, 17]])

np.hstack([a,b])

array([[ 0, 1, 2, 3, 12, 13], [ 4, 5, 6, 7, 14, 15], [ 8, 9, 10, 11, 16, 17]])

np.column_stack([a,b])

array([[ 0, 1, 2, 3, 12, 13], [ 4, 5, 6, 7, 14, 15], [ 8, 9, 10, 11, 16, 17]])